package main

import (
	"fmt"
	"runtime"
)

func Trace01(name string) func() {
	fmt.Println("enter : " + name)
	return func() {
		fmt.Println("exist :" + name)
	}
}

func Trace02() func() {
	// runtime.Caller 函数获得当前 Goroutine 的函数调用栈上的信息，runtime.Caller 的参数标识的是要获取的是哪一个栈帧的信息。
	// 当参数为 0 时，返回的是 Caller 函数的调用者的函数信息，就是 Trace 函数。需要的是 Trace 函数的调用者的信息，于是传入 1
	// 第一个返回值代表的是程序计数（pc）；第二个和第三个参数代表对应函数所在的源文件名以及所在行数
	pc, _, _, ok := runtime.Caller(1)
	if !ok {
		panic("not found caller")
	}

	fn := runtime.FuncForPC(pc)
	name := fn.Name()
	fmt.Println("enter : " + name)
	return func() {
		fmt.Println("exist :" + name)
	}
}

//  foo 函数中的defer Trace("foo")()，Go 会对 defer 后面的表达式Trace("foo")()进行求值。
// 由于这个表达式包含一个函数调用Trace("foo"), 所以这个函数会被执行。
func foo() {
	// defer Trace01("foo")()
	defer Trace02()()
	bar()
}

func bar() {
	// defer Trace01("bar")()
	defer Trace02()()
}

func main() {
	// 执行高阶的函数
	// defer Trace01("main")()
	defer Trace02()()
	foo()

}
